﻿using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Debugger.Interop;
using Red.Scripts.Debugger.Defines;
using AD7 = Red.Scripts.Debugger.Engine;

namespace Red.Scripts.Debugger.Remote.Debugger
{
    [ComVisible( true )]
    [Guid( Defines.CLSID.Raw.Engine )]
    public class Engine : AD7.AD7Engine
    {
        #region IDebugEngine2

        // Attach the debug engine to a program. 
        // https://msdn.microsoft.com/en-us/library/bb147141.aspx
        public override int Attach( IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason )
        {
            Postman = new AD7.Events.Postman( this, ad7Callback );

            // 2. Call the GetProgramId method on the IDebugProgram2 object that was passed to the IDebugEngine2::Attach method.
            // This returns a GUID that is used to identify the program. The GUID must be stored in the object that represents the local
            // program to the DE, and it must be returned when the IDebugProgram2::GetProgramId method is called on the IDebugProgram2 interface.

            // Note - We need to create a new IDebugProgram2 that is not the same as the one enumerated by the Port/Supplier
            Guid programGuid;
            rgpPrograms[ 0 ].GetProgramId( out programGuid );

            Remote.Program program = rgpPrograms[ 0 ] as Remote.Program;

            if ( program != null )
            {
                Program debuggedProgram = new Program( programGuid, Postman, program, Breakpoints );

                if ( debuggedProgram.Connect( 100 ) )
                {
                    DebuggedProgram = debuggedProgram;
                    Breakpoints.DebuggedProgram = DebuggedProgram;

                    // 1. Send an IDebugEngineCreateEvent2 event object to the SDM
                    Postman.SendEngineCreatedEvent();

                    // 3. Send an IDebugProgramCreateEvent2 event object to notify the SDM that the local IDebugProgram2 object was created to represent the program to the DE
                    Postman.SendProgramCreatedEvent( debuggedProgram );

                    return Constants.S_OK;
                }
            }

            return Constants.E_ABORT;
        }

        #endregion IDebugEngine2

        #region IDebugEngineLaunch2

        // Resume a process launched by IDebugEngineLaunch2.LaunchSuspended
        public override int ResumeProcess( IDebugProcess2 process )
        {
            UriProcess uriProcess = process as UriProcess;

            if ( uriProcess != null )
            {
                IDebugPort2 port;
                process.GetPort( out port );

                IDebugDefaultPort2 defaultPort = (IDebugDefaultPort2)port;

                IDebugPortNotify2 portNotify;
                defaultPort.GetPortNotify( out portNotify );

                portNotify.AddProgramNode( new Remote.Program( uriProcess ) );

                return Constants.S_OK;
            }

            return Constants.E_FAIL;
        }

        #endregion IDebugEngineLaunch2
    }
}
